package ace.cmp.data.methodname.method.name.sql.core.resolver.impl;

import ace.cmp.data.methodname.method.name.sql.core.enums.SqlCommandTypeEnum;
import ace.cmp.data.methodname.method.name.sql.core.resolver.MethodNameToSubjectResolver;
import ace.cmp.data.methodname.method.name.sql.core.util.StringUtils;
import java.util.Arrays;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author caspar
 * @date 2023/2/18 16:27
 */
public class MethodNameToSubjectResolverImpl implements MethodNameToSubjectResolver {
  private final String methodName;
  private static final String KEY_DISTINCT = "Distinct";

  /**
   * find|get|delete|.....
   */
  private static final String KEY_ALL_SQL_DML_KEYWORD_REGEX =
      String.join("|", SqlCommandTypeEnum.getAllKeyWords());

  /**
   * 获取列原始字符串
   */
  private static final String MATCH_SUBJECT_SOURCE_STRING_PATTERN_VALUE_TEMPLATE = "^(%s).*?By";

  private static final String MATCH_SUBJECT_SOURCE_STRING_PATTERN_VALUE =
      String.format(
          MATCH_SUBJECT_SOURCE_STRING_PATTERN_VALUE_TEMPLATE, KEY_ALL_SQL_DML_KEYWORD_REGEX);
  private static final Pattern MATCH_SUBJECT_SOURCE_STRING_PATTERN =
      Pattern.compile(MATCH_SUBJECT_SOURCE_STRING_PATTERN_VALUE);

  /**
   * 获取top first 关键字的数字字符串
   */
  private static final String MATCH_TOP_STRING_ONLY_NUMBER_PATTERN_VALUE =
      String.format("(?<=.*)(?<=(Top|First))[\\d]+(?=.*)", KEY_ALL_SQL_DML_KEYWORD_REGEX);

  private static final Pattern MATCH_TOP_STRING_ONLY_NUMBER_PATTERN =
      Pattern.compile(MATCH_TOP_STRING_ONLY_NUMBER_PATTERN_VALUE);

  /**
   * 获取Distinct 关键字位置字符串
   */
  private static final String MATCH_DISTINCT_STRING_PATTERN_VALUE =
      String.format("%s", KEY_DISTINCT);

  private static final Pattern MATCH_DISTINCT_STRING_PATTERN =
      Pattern.compile(MATCH_DISTINCT_STRING_PATTERN_VALUE);

  public MethodNameToSubjectResolverImpl(String methodName) {
    this.methodName = methodName;
  }

  @Override
  public String getMethodName() {
    return this.methodName;
  }

  @Override
  public SqlCommandTypeEnum getSqlCommandType() {
    String methodName = this.methodName;

    Optional<SqlCommandTypeEnum> sqlCommandTypeEnumOptional =
        Arrays.stream(SqlCommandTypeEnum.values())
            .filter(sqlDmlTypeEnum -> this.methodNameMatchTheKeyWord(methodName, sqlDmlTypeEnum))
            .findFirst();

    if (sqlCommandTypeEnumOptional.isEmpty()) {
      throw new IllegalArgumentException(
          String.format("method : %s can't resolve sql command type", methodName));
    }

    return sqlCommandTypeEnumOptional.get();
  }

  @Override
  public String getSubjectSourceString() {
    Matcher matcher = MATCH_SUBJECT_SOURCE_STRING_PATTERN.matcher(methodName);
    if (matcher.find()) {
      return matcher.group();
    }
    return StringUtils.EMPTY;
  }

  @Override
  public Optional<Integer> getTopNumber() {
    String columnString = this.getSubjectSourceString();
    Matcher topStringOnlyNumberMatcher = MATCH_TOP_STRING_ONLY_NUMBER_PATTERN.matcher(columnString);
    if (topStringOnlyNumberMatcher.find() == false) {
      return Optional.empty();
    }
    String topStringOnlyNumber = topStringOnlyNumberMatcher.group();
    Integer number = Integer.parseInt(topStringOnlyNumber);
    return Optional.ofNullable(number);
  }

  @Override
  public Boolean getDistinct() {
    String columnString = this.getSubjectSourceString();
    return MATCH_DISTINCT_STRING_PATTERN.matcher(columnString).find();
  }

  private boolean methodNameMatchTheKeyWord(
      String methodName, SqlCommandTypeEnum sqlCommandTypeEnum) {
    Pattern pattern =
        Pattern.compile(
            String.format(
                MATCH_SUBJECT_SOURCE_STRING_PATTERN_VALUE_TEMPLATE,
                String.join("|", sqlCommandTypeEnum.getKeywords())));
    return pattern.matcher(methodName).find();
  }
}
